﻿using Microsoft.WindowsAPICodePack.Taskbar;
using Serietheque.Fenetres;
using Serietheque.Properties;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.Entity;
using System.Data.Entity.Validation;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Threading;
using TvdbLib.Data;

namespace Serietheque
{
    partial class MainWindow : Window, INotifyPropertyChanged, IDisposable
    {
        #region Membres

        private BackgroundWorker m_bwAjoutBiblio;
        private BackgroundWorker m_bwChercherNom;
        private BackgroundWorker m_bwConsolidation;
        private BackgroundWorker m_bwFollowed;
        #endregion Membres

        /// <summary>
        /// Creation d'un objet Episodes depuis le nom d'un fichier.
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        private static Episodes CreateEpisode(string fileName)
        {
            EpisodesTempo epT = new EpisodesTempo(fileName);

            if (epT.Ok && epT != null)
            {
                Episodes ep = new Episodes();
                ep.Num = epT.Episode;//Num de l'épisode

                Saisons sa = new Saisons();
                sa.Num = epT.Saison;//Num de la saison

                Series se = new Series();
                se.Name = epT.Serie;//Nom de l'épisode

                //Qualité et team

                return ep;
            }
            else
                return null;
        }

        private void InitializeBackgroundWorker(BackgroundWorker bw, int numero)
        {
            if (numero == 1) //ajout biblio
            {
                bw.DoWork += new DoWorkEventHandler(bwAddBdd_DoWork);
                bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwAddBdd_RunWorkerCompleted);
                bw.ProgressChanged += new ProgressChangedEventHandler(bwAddBdd_ProgressChanged);
                bw.WorkerReportsProgress = true;
                bw.WorkerSupportsCancellation = true;
                stackPanelHistorique.IsExpanded = true;
                StopBtn.IsEnabled = true;
            }
            //else if (numero == 2)
            //{
            //    bw.DoWork += new DoWorkEventHandler(bwSearchEpisodeName_DoWork);
            //    bw.WorkerReportsProgress = false;
            //    bw.WorkerSupportsCancellation = false;
            //    bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwSearchEpisodeName_RunWorkerCompleted);
            //}
            //else if (numero == 3)
            //{
            //    bw.DoWork += new DoWorkEventHandler(bwConsolidation_DoWork);
            //    bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwConsolidation_RunWorkerCompleted);
            //    bw.ProgressChanged += new ProgressChangedEventHandler(bwConsolidation_ProgressChanged);
            //    bw.WorkerReportsProgress = true;
            //    bw.WorkerSupportsCancellation = true;
            //}
            if (numero == 4) //followed
            {
                bw.DoWork += new DoWorkEventHandler(bwFollowed_DoWork);
                bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwFollowed_RunWorkerCompleted);
                bw.ProgressChanged += new ProgressChangedEventHandler(bwFollowed_ProgressChanged);
                bw.WorkerReportsProgress = true;
                bw.WorkerSupportsCancellation = true;
            }


        }

        #region Follow

        private void bwFollowed_DoWork(object sender, DoWorkEventArgs e)
        {
            //BackgroundWorker worker = sender as BackgroundWorker;

            //Boucle sur toutes les séries suivit
            foreach (Series serie in (List<Series>)e.Argument)
            {
                Tvdb tvdb = new Tvdb();//declaration tvdb

                TvdbSeries tvdbSerie = tvdb.GetSerieFull((int)serie.IdTvdb);//recup de la serie tvdb

                tvdb.UpdateSerieData(serie);

                //if (tvdbSerie.Status == "Ended") //uniquement les series en cours ou en pause
                //    continue;

                //boucle sur tous les épsiodes de la série sur tvdb
                foreach (TvdbEpisode tvdbEpisode in tvdbSerie.Episodes)
                {
                    Saisons saison = null; //déclaration de la saison

                    if (Settings.Default.FollowOnlyLast && tvdbEpisode.SeasonNumber == tvdbSerie.NumSeasons)//on prend la derniere saison en cours ur tvdb
                        saison = serie.Saisons.FirstOrDefault(s => s.Num == tvdbSerie.NumSeasons); // choisir la dernier saison
                    else
                        continue;//TODO
                    //saison = serie.Saisons.FirstOrDefault(s => s.Num == te.SeasonNumber); //si la saison existe

                    Episodes episode = null;//declaration episode

                    if (saison != null) //si la saison existe
                    {
                        episode = saison.Episodes.FirstOrDefault(ep => ep.Num == tvdbEpisode.EpisodeNumber);//on prend l'episode par son numéro dans la saison
                    }
                    else //sinon on créé la saison
                    {
                        saison = new Saisons();
                        saison.Num = tvdbEpisode.SeasonNumber;
                        saison.IdTvdb = tvdbEpisode.SeasonId;
                        saison.Name = "Saison " + tvdbEpisode.SeasonNumber;

                        serie.Saisons.Add(saison); //et on ajoute la saison a la serie
                    }

                    if (episode == null)//si l'épisode n'existe pas on créé l'épisode
                    {
                        episode = new Episodes();
                        episode.Num = tvdbEpisode.EpisodeNumber;
                        episode.Name = tvdbEpisode.EpisodeName;
                        episode.Overview = tvdbEpisode.Overview;
                        episode.AirDate = tvdbEpisode.FirstAired.Date;
                        
                        if (episode.AirDate.Value.Year == 0001)
                        {
                            episode.AirDate = episode.AirDate.Value.AddYears(1990);
                        }
                        episode.IdTvdb = tvdbEpisode.Id;
                        saison.Episodes.Add(episode);//et on ajoute l'épisode a la saison.
                    }
                    else
                    {
                        tvdb.UpdateEpisodeData(episode);
                    }
                }

                SaveChanges(seriesContext);
            }
        }

        private void bwFollowed_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            //progressbar ou truc rond pour dire que ca bosse
        }

        private void bwFollowed_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            HideProgress();
        }

        /// <summary>
        /// pour ajouter les episodes pas encore téléchargé des series à suivre
        /// </summary>
        private void Followed()
        {
            seriesContext.SaveChanges();
            seriesContext.Series.Load(); // charge les series
            List<Series> ss = (from s in seriesContext.Series //on prend les serie "followed"
                               where s.Followed == true
                               select s).ToList();

            if (ss != null) //si il y a des series followed on lance le bgw
            {
                m_bwFollowed = new BackgroundWorker();
                //Initialisation bgw
                InitializeBackgroundWorker(m_bwFollowed, 4);
                //Lancement du bgw
                m_bwFollowed.RunWorkerAsync(ss);
                ShowProgress(true);
            }
        }
        #endregion Follow

        #region AjoutBiblio

        private void bwAddBdd_DoWork(object sender, DoWorkEventArgs e)
        {

            BackgroundWorker worker = sender as BackgroundWorker;
            List<string> fichiers = e.Argument as List<string>;

            int n = 0; //nombre de fichier traiter
            int y = fichiers.Count; //nombre total de fichier

            Tvdb tvdb = new Tvdb();

            foreach (string chemin in fichiers)
            {
                //création de l'épisode a revoir.
                n++;

                if (worker.CancellationPending) // Si l'utilisateur annule le travaille
                {
                    e.Cancel = true;
                    break;
                }

                string historique = null;  //pour l'historique

                string ext = Path.GetExtension(chemin);//recupere l'extension du fichier a travailler

                EpisodesTempo episodeTempo = new EpisodesTempo(Path.GetFileNameWithoutExtension(chemin));//création episode temporaire, TODO

                //initialisation
                Series serie = null;
                Episodes episode = null;
                Saisons saison = null;

                //Historique : sur quoi on travaille :
                historique += Environment.NewLine;
                historique += (ext == ".avi" || ext == ".mkv" || ext == ".mp4") ? "[VIDEO] - " : "[SOUS-TITRE] - ";//Cast si on travaille sur du sous titre ou du fichier video
                historique += Path.GetFileNameWithoutExtension(chemin);

                #region Si le regex de marche pas ou à foirer
                if (episodeTempo == null || !episodeTempo.Ok)//A Revoir
                {
                    TaskbarManager.Instance.SetProgressState(TaskbarProgressBarState.Paused);
                    this.Dispatcher.Invoke(DispatcherPriority.Normal, (ThreadStart)delegate //Pour ouvrir sur un autre thread
                    {
                        //Episode temp = new Episode();
                        EditEpisodeWindow editEpisodeWindow = new EditEpisodeWindow(episodeTempo);
                        editEpisodeWindow.Topmost = true;
                        editEpisodeWindow.ShowDialog();

                        if (editEpisodeWindow.DialogResult.Value == true)
                        {
                            if (episodeTempo.Serie != null)
                                episodeTempo.Ok = true;
                        }
                    });
                    TaskbarManager.Instance.SetProgressState(TaskbarProgressBarState.Normal);
                }
                #endregion

                if (episodeTempo != null && episodeTempo.Ok) // si episode non null on attaque les travaux
                {

                    //on va retrouver la serie correspondante


                    //on cherche id de la serie a cours
                    //int idSerie = tvdb.SerieIdByTvdb(ept.Serie);
                    int idSerie = tvdb.GetSerieId(episodeTempo.Serie);

                    //if (idSerie != 0) // si l'id de la serie a été trouvé                

                    //on cherche l'episode
                    episode = seriesContext.Episodes.Where(ep => (ep.Saisons.Series.IdTvdb == idSerie || ep.Saisons.Series.Name == episodeTempo.Serie) && ep.Saisons.Num == episodeTempo.Saison && ep.Num == episodeTempo.Episode).FirstOrDefault();

                    //Si l'épisode existe et il n'est pas possédé.
                    if (episode != null)
                    {
                        serie = episode.Saisons.Series;
                        saison = episode.Saisons;
                        //on utilise l'épisode et on rajoute les infos sur le chemin, la date d'ajout (et les sub).                       
                        if (ext != ".srt")
                        {
                            episode.FilePath = chemin;
                            episode.AddDate = DateTime.Now;
                        }
                        else
                            if (!episode.Sub.GetValueOrDefault(false))
                            {
                                episode.Sub = true;
                                episode.SubPath = chemin;
                                SaveChanges(seriesContext);
                            }
                            else { }//boite de dialogue "voulez vous remplacé le sub ?"
                    }
                    else
                    {
                        //sinon on créé l'épisode et on cherche la saison et la serie correspondante
                        episode = new Episodes();
                        episode.Num = episodeTempo.Episode; //ajout du numéro de l'épisode
                        //ajout du chemin de l'épisode/sub
                        if (ext == ".srt")
                        {
                            episode.SubPath = chemin;
                            episode.Sub = true;
                        }
                        else
                        {
                            episode.FilePath = chemin;
                            episode.Taille = new FileInfo(episode.FilePath).Length;
                            episode.AddDate = DateTime.Now;
                        }

                        //on va chercher si la serie est deja presente
                        serie = idSerie != 0 ?
                            seriesContext.Series.Where(s => s.IdTvdb == idSerie).FirstOrDefault() :
                            seriesContext.Series.Where(s => s.Name == episodeTempo.Serie).FirstOrDefault();

                        //si la serie n'existe pas
                        if (serie == null)
                        {
                            //on créer la serie avec diverse info
                            serie = new Series();
                            serie.IdTvdb = idSerie;
                            tvdb.UpdateSerieData(serie);//update les info de la serie.
                            //serie.Name = tvdb.GetSerieName(idSerie);
                            seriesContext.Series.Add(serie); //ajout de la serie au context 
                        }
                        //on cherche la saison de l'épisode si non retourne null si non existente
                        saison = serie.Saisons.Where(b => b.Num == episodeTempo.Saison).FirstOrDefault();

                        if (saison == null) //si la saison n'existe pas c'est que l'épisode ne peut pas etre present on la créer.
                        {
                            saison = new Saisons();//creation saison
                            saison.Num = episodeTempo.Saison;         //info saison
                            saison.Name = "Saison " + episodeTempo.Saison;
                        }


                        saison.Episodes.Add(episode); //ajout episode à la saison
                        serie.Saisons.Add(saison);//ajout saison à serie.
                        SaveChanges(seriesContext);
                    }

                    if (episode != null)
                    {
                        if (episode.Saisons.Series != null)
                            if (!episode.Saisons.Series.IsValide())
                                tvdb.UpdateSerieData(serie);
                        if (ext == ".srt")
                            //    SaveChanges(seriesContext);
                            //else
                            UndoUpdates(seriesContext);

                        //update data depuis thetvdd
                        tvdb.UpdateEpisodeData(episode);
                        //episode.AirDate = null;
                        string newChemin = episode.CheminFichierEpisode() + ext;

                        if (newChemin != null && !File.Exists(newChemin))
                            try
                            {
                                if (!Directory.Exists(Path.GetDirectoryName(newChemin)))
                                {
                                    try
                                    {

                                        Directory.CreateDirectory(Path.GetDirectoryName(newChemin));
                                    }
                                    catch (Exception)
                                    {

                                        throw;
                                    }

                                }
                                if (Directory.Exists(Path.GetDirectoryName(newChemin)))
                                {
                                    File.Move(chemin, newChemin);
                                    //Maj de l'épisode
                                    if (ext != ".srt")
                                        episode.FilePath = newChemin;
                                }

                                historique += " ----> " + episode.ToString();
                            }
                            catch (IOException ex)
                            {
                                historique += " ----> Non déplacé car :" + ex.Message;
                                //throw new IOException();
                            }
                        else if (File.Exists(newChemin))
                            historique += " ---> Le fichier existe déjà dans " + Path.GetDirectoryName(newChemin);
                    }
                    else
                        UndoUpdates(seriesContext);

                }
                else //episode incorrect
                    historique += "Episode incorrect";

                int pourcent = (int)(((double)n) / (double)y * 100); //Calcul pourcentage
                worker.ReportProgress(pourcent, historique);//Maj de la progressbar
                historique += Environment.NewLine; //nouvelle ligne pour un nouvel épisode
            }//fin foreach
        }

        private void bwAddBdd_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            //episode[0], historique[1], indexFichier[2]
            //string userState = e.UserState as string;

            //historique
            historiqueTb.Text += e.UserState as string; //Historique
            historiqueSv.PageDown();

            //TxtBlock nombre de files restant
            int txtDropTxt = Int32.Parse(txtDrop.Text) != 0 ? Int32.Parse(txtDrop.Text) - 1 : 0;
            txtDrop.Text = txtDropTxt.ToString();

            //progressbar
            progressBarDrop.Value = e.ProgressPercentage;
            TaskbarManager.Instance.SetProgressValue(e.ProgressPercentage, 100); //TaskBar
        }

        private void bwAddBdd_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled == true)
            {
                historiqueTb.Text += "Annulé !!" + Environment.NewLine;
                TaskbarManager.Instance.SetProgressState(TaskbarProgressBarState.Error);
            }
            //else
            //historiqueTb.Text += "Terminé !";
            historiqueTb.Text += Environment.NewLine;

            // MessageBox.Show("Traitement des files terminé");

            //On fait disparait le bouton stop !
            StopBtn.Visibility = Visibility.Collapsed;
            StopBtn.IsEnabled = false;

            //Fin du bw, retour à la normal
            m_bwAjoutBiblio.Dispose();
            m_bwAjoutBiblio = null;

            //Retour la normal
            Main.AllowDrop = true; //réautosire le drop                   



            HideProgress();
            seriesContext.SaveChanges();
            //ShowAllEpisodes();
            DataGridEpisodes.Items.Refresh();
        }

        private void FilesTreatment(List<string> files)
        {
            //Désactivation datagrid, progressbars visibles, création bw, expander expensé
            //ShowAllEpisodes();
            GridProgressBar.Visibility = Visibility.Visible;
            progressBarDrop.Value = 0;
            txtDrop.Text = files.Count.ToString();

            m_bwAjoutBiblio = new BackgroundWorker();
            //Initialisation bgw
            InitializeBackgroundWorker(m_bwAjoutBiblio, 1);
            //Lancement du bgw
            m_bwAjoutBiblio.RunWorkerAsync(files);
            ShowProgress(false);
        }
        #endregion AjoutBiblio

        #region Fonction




        public static string doRegex(string text)
        {
            return Regex.Replace(text, @"([#/\$!*:<>\?])", "");
        }
        #endregion

        void IDisposable.Dispose()
        {
            throw new NotImplementedException();
        }
    }
}